package com.geek;

import javax.interceptor.AroundInvoke;
import javax.interceptor.InvocationContext;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

/**
 * 实现拦截器 调用链
 */
public class ChainInvocationContext implements InvocationContext {

    private final InvocationContext delegate;

    private final Object[] interceptors;

    private final int length;

    private final Map<Object,Method> interceptorMethodMap;

    private int pos;

    public ChainInvocationContext(InvocationContext delegate, Object... interceptors) {
        this.delegate = delegate;
        this.interceptors = interceptors;
        length = interceptors.length;
        interceptorMethodMap = initInterceptorMethodMap();
    }

    /**
     * 找到interceptors中方法被标记@AroundInvoke的方法, 切参数符合要求
     * @return
     */
    private Map<Object, Method> initInterceptorMethodMap() {
        Map<Object, Method> result = new HashMap<>();
        for (Object interceptor : interceptors) {
            result.put(interceptor, findAroundInvokeMehod(interceptor));
        }
        return result;
    }

    private Method findAroundInvokeMehod(Object interceptor) {
        //所有public ; 包括父类
        for (Method declaredMethod : interceptor.getClass().getMethods()) {
            int modifiers = declaredMethod.getModifiers();
            if (Modifier.isStatic(modifiers)) {
                continue;
            }
            if (declaredMethod.getParameterCount() != 1) {
                continue;
            }
            if (declaredMethod.isAnnotationPresent(AroundInvoke.class)
                    && InvocationContext.class.isAssignableFrom(declaredMethod.getParameterTypes()[0])) {
                return declaredMethod;
            }
        }
        return null;
    }


    @Override
    public Object getTarget() {
        return delegate.getTarget();
    }

    @Override
    public Object getTimer() {
        return delegate.getTimer();
    }

    @Override
    public Method getMethod() {
        return delegate.getMethod();
    }

    @Override
    public Constructor<?> getConstructor() {
        return delegate.getConstructor();
    }

    @Override
    public Object[] getParameters() {
        return delegate.getParameters();
    }

    @Override
    public void setParameters(Object[] objects) {
        delegate.setParameters(objects);
    }

    @Override
    public Map<String, Object> getContextData() {
        return delegate.getContextData();
    }

    @Override
    public Object proceed() throws Exception {
        if (pos < length) {
            Object interceptor = interceptors[pos++];
            //执行
            Method method = interceptorMethodMap.get(interceptor);
            return method.invoke(interceptor, this);
        }
        return delegate.proceed();
    }

}
